package com.gin.kotlin.gf2gamecommunity.app

import android.app.Application
import android.util.Log
import androidx.room.Room
import com.gin.kotlin.form.LoginForm
import com.gin.kotlin.gf2gamecommunity.base.LogInterceptor
import com.gin.kotlin.gf2gamecommunity.base.util.setCoilDefaultClient
import com.gin.kotlin.gf2gamecommunity.base.util.toast
import com.gin.kotlin.gf2gamecommunity.base.util.toastDev
import com.gin.kotlin.gf2gamecommunity.database.GF2Database
import com.gin.kotlin.main.Gf2BbsApi
import com.gin.kotlin.response.Res
import com.gin.kotlin.response.account.LoginBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.InterruptedIOException
import java.net.ConnectException
import java.net.UnknownHostException
import java.time.ZonedDateTime
import java.util.concurrent.TimeUnit

class App : Application() {
    lateinit var versionName: String
    lateinit var database: GF2Database
    lateinit var api: Gf2BbsApi

    // 发帖后设置为 true
    var replyFlag = false

    override fun onCreate() {
        super.onCreate()
        INSTANCE = this
        this.versionName = packageManager.getPackageInfo(packageName, 0).versionName

        // 初始化数据库
        this.database =
            Room.databaseBuilder(this, GF2Database::class.java, GF2Database::class.java.simpleName)
                // 版本硬升级，正式版需移除
                .fallbackToDestructiveMigration()
                .allowMainThreadQueries()
                .build()

        initApi()

        setCoilDefaultClient()
    }

    fun currentAccount() = this.database.gF2AccountDao().findCurrent()

    /**
     * 初始化API
     */
    fun initApi() {
        // 从数据库中加载当前账号
        val account = currentAccount()

        if (account == null) {
            // 如果账号不存在，则创建无令牌api
            this.api = buildApi()
        } else if (account.expire.isBefore(ZonedDateTime.now())) {
            // 如果令牌已过期，创建无令牌api并使用记录的账号密码尝试登录
            this.api = buildApi()
            this.api.accountApi.login(LoginForm(account.username, account.password, true))
                .enqueue(object : Callback<Res<LoginBody>?> {
                    override fun onResponse(
                        p0: Call<Res<LoginBody>?>,
                        response: Response<Res<LoginBody>?>
                    ) {
                        val loginBody = response.body()?.data?.account

                        if (loginBody != null) {
                            loginBody.apply {
                                val expire = ZonedDateTime.now().plusDays(2)
                                Log.i(
                                    TAG,
                                    "自动登录, uid: ${account.username}, 令牌有效期: $expire"
                                )
                                database.gF2AccountDao().updateToken(uid!!, token!!, expire)
                            }
                        } else {
                            App.toast("自动登录失败: ${response.message()}")
                        }
                    }

                    override fun onFailure(p0: Call<Res<LoginBody>?>, throwable: Throwable) {
                        onFailed(throwable)
                    }
                })
        } else {
            Log.i(
                TAG,
                "自动装载, uid: ${account.username}, 令牌有效期: ${account.expire.toLocalDateTime()}"
            )
            // 令牌未过期，创建有令牌api
            this.api = buildApi(account.token)
        }
    }

    companion object {
        const val HOST = "https://gf2-bbs.exiliumgf.com"
        private val TAG = App::class.java.simpleName
        lateinit var INSTANCE: App
        fun toast(message: String) = INSTANCE.toast(message)
        fun toastDev(message: String = "...") = INSTANCE.toastDev(message)
        fun buildApi(authorization: String? = null) =
            Gf2BbsApi.Builder(authorization = authorization)
                .client {
                    it.addInterceptor(LogInterceptor())
                        .callTimeout(60, TimeUnit.SECONDS)
                        .connectTimeout(60, TimeUnit.SECONDS)
                        .readTimeout(60, TimeUnit.SECONDS)
                }
                .build()

        fun onFailed(throwable: Throwable) = when (throwable) {
            is InterruptedIOException -> toast("请求失败请重试: ${throwable.message}")
            is UnknownHostException, is ConnectException -> toast("网络似乎已断开")
            else -> {
                toast("未知异常")
                throwable.printStackTrace()
            }
        }
    }
}
